ISA, Instructions and CPU

1. 计算机系统的抽象

我们都明白,计算机系统可以分成两类功能上的实体——计算机硬件计算机软件。但是软件和硬件是两个很宽泛的概念,继续划分,我们可以将整个计算机系统划分成 7 层结构:

  1. 应用(问题)
  2. 算法
  3. 编程(语言)
  4. 指令集体系结构(Instruction Set Architecture, ISA)
  5. 微体系结构
  6. 功能部件的电路设计
  7. 器件
    在这 7 层结构中软件层面包括应用、算法、编程和ISA,硬件层面包含有ISA、微体系结构、电路设计和器件。你发现了么?软件层面包含ISA,硬件层面也包括了ISA,那ISA到底是何方神圣,脚踏两条船?

在我们学习操作系统的时候,可能会听老师说:“操作系统是介于软件和硬件之间最接近硬件的软件,为软件间接提供操作硬件的接口“。通过上面对ISA极其模糊的介绍之后,你会不会有很多关于ISA和操作系统的疑惑?我们下面来看看ISA究竟是什么东西。

2. ISA和指令

ISA是指令集体系结构,它对于硬件而言是一种设计上的规约,而对于操作系统而言ISA提供API的接口。我们常听说ARM、MIPS、x86等这些就对应着不同的ISA。既然叫指令集体系结构,那它肯定和指令有着密不可分的关系,对于硬件来说,ISA是一种规约,它规定了CPU需要为哪些指令提供接口(例如:加减乘除与或非),而至于具体的实现?那完全是微体系结构的事情。(ISA关心的是有没有乘法器、乘法指令的事情,微体系结构关心的是乘法器如何实现的事情。

我们举例子直观来感受一下ISA对上层操作系统提供的指令集接口,我们用ARM和x86举例子:

  1. 加载寄存器

    • ARMLDR R0, [R1]
      • 二进制表示: 1110 0101 1000 0000 0000 0000 0000 0000
    • x86MOV EAX, [EBX]
      • 二进制表示: 1000 1011 0000 0000
  2. 加法操作

    • ARMADD R0, R1, R2
      • 二进制表示: 1110 0000 1000 0001 0000 0000 0000 0010
    • x86ADD EAX, EBX
      • 二进制表示: 0000 0001 1100 0011
  3. 存储寄存器

    - **ARM**: `STR R0, [R1]`
        - 二进制表示: `1110 0101 0000 0000 0000 0000 0000 0000`
    - **x86**: `MOV [EBX], EAX`
        - 二进制表示: `1000 1001 0000 0000`
    

    发现了么?ISA不同,实现相同功能的指令就是不一样的。这也就是为什么你写的程序不能在其他平台上运行,这里的平台指的就是ISA。

2.1 设计自己的ISA

如果我们的只有定长的8位指令,我们如何设计自己的ISA?我们下面给出规约:

2.1.1 系统的硬件实现

系统应当有6个寄存器(REG0-REG5),一个输入端,一个输出端。

2.1.2 系统的指令集

用高两位用来表示指令的类型:

  • 00表示立即数指令,我们规定立即数指令总是将立即数送给REG0;

  • 01表示计算指令,这部分指令由ALU实现,我们进行如下规定:

    1. 01 000 000表示OR指令
    2. 01 000 001表示NAND指令
    3. 01 000 010表示NOR指令
    4. 01 000 011表示AND指令
    5. 01 000 100表示ADD指令
    6. 01 000 101表示SUB指令

    我们可以向立即数指令一样,设置某个特定的寄存器用于特定的作用,如:算数操作永远是将REG1和REG2中读取数值作为输入的操作数,并将结果写入REG3中。

  • 10表示复制指令,将源的数据送到目的,我们进行如下规定:

    1. 10 000(SRC) 000(DEST)高两位表示类型,中间三位表示源,后三位表示目的。
    2. 000-101表示从REG0-REG5的寄存器,中间三位为110时表示从输入端读数据,后三位为110时表示将源数据送到输出端。
  • 11表示条件判断指令,只有满足条件才会将数据输出,我们给出如下规定:

    1. 11 000 000表示永不输出
    2. 11 000 001表示输入=0时输出
    3. 11 000 010表示输入<0时输出
    4. 11 000 011表示输入≤0时输出
    5. 11 000 100表示永远输出
    6. 11 000 101表示输入≠0时输出
    7. 11 000 111表示输入>0时输出

2.2 将机器指令转换为汇编

汇编,我们可以理解为机器码的别名,每一条汇编指令都可以对于某一个特定的指令。依此,我们可以将机器码通过添加汇编别名方便地为人类理解,如:

add ;01 000 100
sub ;01 000 101

mov_reg0_reg5 ;10 000 101
mov_in_out ;10 110 110

等等。看到了么?在我们的指令系统中,操作系统可以用add指令来与底层的裸机进行交互,告诉机器我现在要让你把REG1和REG2的数据相加放到REG3中。

3. ISA和CPU

根据上面我们的指令集体系结构的规约,我们就可以设计自己的CPU了。

3.1 译码器

首先,我们需要译码器帮助我们用高两位将不同功能的指令给筛选出来,这里,我们简单用分线器将 8 位指令分成 8 个输入端,取高两位用2-4译码器来完成译码的工作。当高两位为00就使能立即数操作的工作逻辑,为01就使能ALU,以此类推。